﻿using System;
using System.Collections.Generic;

namespace DimensionsHelper.Common.Metadata.Script;

/// <summary>
///     分类常量值表达式。使用名称定义时，需要有效的元数据检索对象<see cref="Expression.MetadataProvider" />。
/// </summary>
public class CategoricalExpression : LiteralExpression
{
    private readonly List<CategoryExpression> _elements = [];


    // 存储在当前元数据上下文下扩展后的结果。
    private Categorical? _resolved;

    /// <summary>
    ///     分类常量值表达式。使用名称定义时，需要有效的元数据检索对象<see cref="Expression.MetadataProvider" />。
    /// </summary>
    public CategoricalExpression(int start) : base(LiteralKinds.Categorical, start)
    {
    }

    /// <summary>
    ///     分类表达式的元素列表。
    /// </summary>
    public IReadOnlyList<CategoryExpression> Elements => _elements;

    /// <summary>
    ///     向当前表达式末尾追加新的分类元素表达式。
    /// </summary>
    /// <param name="element"></param>
    internal void Add(CategoryExpression element)
    {
        _elements.Add(element);
        element.Parent = this;
    }

    private void FetchRange(ref IList<string>? definitions, CategoryExpression item, Action<string> callback)
    {
        if (string.IsNullOrEmpty(MetadataContext))
        {
            throw new Exception($"表达式没有元数据上下文字段，位置：{Start}，分类元素表达式：{item.Text}。");
        }

        if (item.Caret && (item.LowerBoundary == null || item.UpperBoundary == null))
        {
            throw new Exception($"无效的分类元素表达式：{item.Text}，位置：{Start}。");
        }

        int i = 0;
        bool metLower = false;

        definitions ??= MetadataProvider.FetchCategoriesDefinition(MetadataContext);

        string lower = item.LowerBoundary?.Text ?? definitions[0];
        string upper = item.UpperBoundary?.Text ?? definitions[definitions.Count - 1];

        while (i < definitions.Count)
        {
            string e = definitions[i];

            if (e.Equals(lower, StringComparison.OrdinalIgnoreCase))
            {
                metLower = true;
            }

            if (metLower)
            {
                callback(e);
            }

            if (e.Equals(upper, StringComparison.OrdinalIgnoreCase))
            {
                break;
            }

            ++i;
        }
    }


    public override ExpressionBasicType Evaluate()
    {
        if (_resolved != null)
        {
            return _resolved;
        }

        var res = new Categorical();

        if (_elements.Count == 0)
        {
            return _resolved = res;
        }

        // 先将排除区间分离
        var ranges = new List<CategoryExpression>();
        var excls = new HashSet<string>();

        IList<string>? definitions = null;

        foreach (CategoryExpression item in _elements)
        {
            if (item.Caret)
            {
                if (string.IsNullOrEmpty(MetadataContext))
                {
                    throw new Exception($"表达式没有元数据上下文字段，位置：{Start}，分类元素表达式：{item.Text}。");
                }

                if (item.LowerBoundary == null || item.UpperBoundary == null)
                {
                    throw new Exception($"无效的分类元素表达式：{item.Text}，位置：{Start}。");
                }

                // 单一值时，直接添加名称
                if (item.LowerBoundary.Text.Equals(item.UpperBoundary.Text, StringComparison.OrdinalIgnoreCase))
                {
                    excls.Add(item.LowerBoundary.Text.ToLower());
                    continue;
                }

                FetchRange(ref definitions, item, str => excls.Add(str.ToLower()));
            }
            else
            {
                ranges.Add(item);
            }
        }

        // 如果只有排除码号，使用定义列表遍历
        if (ranges.Count == 0 && excls.Count != 0)
        {
            ranges.Add(new CategoryExpression(0));
        }

        foreach (CategoryExpression item in ranges)
        {
            // 优先使用整数值。
            if (item.Value != null)
            {
                res.Add(item.Value.Value);
            }
            else
            {
                // 单一名称，直接添加进集合
                if (item is { LowerBoundary: not null, UpperBoundary: not null } &&
                    item.LowerBoundary.Text.Equals(item.UpperBoundary.Text, StringComparison.OrdinalIgnoreCase))
                {
                    res.Add(item.UpperBoundary.Text);
                }
                // 如果是表达式，需要可以检索元数据分类定义列表。
                // {} 是空列表，{^x1..x2} 等同于 {.., ^x1..x2}
                // 同时，排除区间的顺序不重要，{x1..x2, ^y1..y2}等同于{^y1..y2, x1..x2}
                else
                {
                    FetchRange(ref definitions, item, e =>
                    {
                        if (!excls.Contains(e.ToLower()))
                        {
                            res.Add(e);
                        }
                    });
                }
            }
        }

        _resolved = res;
        return res;
    }
}